home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Networking / OTLLCTest / OTLLCTest.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  36.8 KB  |  1,410 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        OTLLCTest.c
  3.  
  4.     Contains:    Simple app write or receive 8022 Ethernet packets using a multicast address
  5.                 This program implements both a sender and receiver such that both sides
  6.                 open an 802.2 Ethernet endpoint. The user can then select whether to run the 
  7.                 program as a sender or receiver. If implemented as a receiver, the endpoint
  8.                 is bound, and the multicast option is turned on. The receiver waits in a 
  9.                 spin loop for a specified period of time before quitting.  The receiver will process
  10.                 all incoming ethernet packets destined to the endpoint for the specified
  11.                 protocol.  Upon receipt, the program checks to see whether the packet was sequential
  12.                 to the previous packet.  A collection of global counter maintains the number of
  13.                 inOrder, outOfOrder packets, and the number of packets reads resulting in an error,
  14.                 plus the number of packets which come in back to back while in the handler.
  15.     
  16.                 Note the this sample turns on the rawmode option so that the handler will be passed the
  17.                 14 byte 802.2 header.
  18.                 Also note that the sender may also implement the rawmode option so that it can also
  19.                 fill in the header bytes itself.  If this is done, then the buffer needs to 
  20.                 be enlarged to include these additional bytes.  These additional bytes will not affect
  21.                 the maximum tsdu size since the tsdu size is the i-frame limit and does not include
  22.                 the header size.
  23.     
  24.                 The sender process, sends 10005 x 1500 byte packets as fast as possible.  The user 
  25.                 can select to to turn on AckSends mode where the packet is handed to OT and not
  26.                 
  27.                 released until OT sends the information to the lower layer. 
  28.     Written by: Rich Kubota    
  29.  
  30.     Copyright:    Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
  31.  
  32.                 You may incorporate this Apple sample source code into your program(s) without
  33.                 restriction. This Apple sample source code has been provided "AS IS" and the
  34.                 responsibility for its operation is yours. You are not permitted to redistribute
  35.                 this Apple sample source code as "Apple sample source code" after having made
  36.                 changes. If you're going to re-distribute the source, we require that you make
  37.                 it clear in the source that the code was descended from Apple sample source
  38.                 code, but that you've made changes.
  39.  
  40.     Change History (most recent first):
  41.                 7/22/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  42.                 01/98                        added threshold timer to control how often WNE gets called.  
  43.                 01/98                        fixed sample so that you can send in raw mode and receive in
  44.                                             regular mode or vice versa and things work.  
  45.                                             Fixed problem that when setting the max data packet size to
  46.                                             1500 bytes and are sending data in regular mode, adjust the
  47.                                             unitdata.data.len field to account for the fact that the
  48.                                             endpoint will insert the LLC header and the SNAP header.  
  49.                                             For raw mode, this is not an issue. Added feature to 1. allow
  50.                                             the program to be re-used without having to quit 2. ask user for
  51.                                             the drivername to use e.g. 'enet0, 'enet1', etc.,
  52.                 01/98                        modified the sample to use the revised NegotiateRawModeOption
  53.                                             code which returns the template type.  The Mentat template driver
  54.                                             returns an additional 24 bytes of info at the beginning of the
  55.                                             raw data packet.
  56.                 01/98                        modified DoBind so that one can use either a regular LLC to SNAP
  57.                                              endpoint.
  58.                 10/97                        fixed bug in OT 8022 module which prevented more than 1483 data
  59.                                             bytes from being sent in raw mode.  Requires OT 1.3 to send > 1483
  60.                                             data bytes with endpoint in rawdata mode.
  61.  
  62. */
  63. #include <stdio.h>
  64. #include <Types.h>
  65. #include <Memory.h>
  66. #include <Resources.h>
  67. #include <Events.h>
  68. #include <OpenTransport.h>            // open transport files            
  69. #include <OpenTptLinks.h>
  70. #include <OpenTptAppleTalk.h>
  71. #include <OpenTptConfig.h>
  72. #include <Time.h>
  73. #include <Errors.h>
  74. #include <String.h>
  75. #include "OTLLCTest.h"
  76. #include "NegotiateRawModeSample.h"
  77.  
  78. // Comment out the following line if synchronous sends desired.
  79. #define __ASYNCSEND__    1
  80.  
  81. //-----------------------------------------------------------------------------------------
  82. // Globals
  83. //-----------------------------------------------------------------------------------------
  84.  
  85. EndpointRef        gEndpoint;
  86. OSStatus        gstatus;
  87. UInt32            gFlags;
  88. UInt32            gNumBack, gNumFore;
  89. UInt32            gPacketsRead;
  90. UInt32            gBackToBackPackets;    
  91. UInt32            gInOrder;
  92. UInt32            gOutOfOrder;
  93. UInt32            gCounter;
  94. UInt32            gNumDataEvents;
  95. UInt32            gReadErrors;
  96. UInt32            gTemplateType;
  97. UInt32            gNumMemErrs;
  98. UInt32            gTimerThreshold;
  99. UInt8            *gBuffer;
  100. UInt8            *gDummyBuffer;
  101. struct T8022Address     gAddr;
  102. UInt8            gmcAddr[k48BitAddrLength] = {MCASTADDR0,MCASTADDR1,MCASTADDR2,MCASTADDR3,MCASTADDR4,MCASTADDR5};
  103. PacketBuffer    gPacket;
  104. UInt8            gFlag1;
  105. Boolean            gDone;
  106. Boolean            gAbort;
  107. //-----------------------------------------------------------------------------------------
  108. // Prototypes
  109. //-----------------------------------------------------------------------------------------
  110. extern OSStatus OTSetMemoryLimits(size_t growSize, size_t mazSize);
  111. OSStatus         DoBind();
  112. OSStatus         DoAddMulticast(EndpointRef ep, unsigned char *mcAddr);
  113. OSStatus        DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr);
  114. void             WriteApplIntro(void);
  115. UInt32             GetYesNoOption(void);
  116. UInt32             GetUserOption(void);
  117. Boolean         CanDoMDATAMode(EndpointRef ep);
  118. void            DoOTLLCWriteTest(void);
  119. Boolean         DoSendPacket(EndpointRef ep);
  120. void            DoOTLLCReadTest(void);
  121. OSStatus         DoReadPacket(EndpointRef ep, UInt8 *mainBuffer);
  122. pascal void     LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie);
  123. void             CallWNE(void);
  124. void            MyIdle(void);
  125. void             DoValueBreak(long value, const char* message);
  126. void             GetDriverName(char *name);
  127. void             SetTimerThreshold(void);
  128. void             PrintAppleTalkPortName(void);
  129. void             ListEnetDrivers(void);
  130.  
  131.  
  132. /*******************************************************************************
  133. ** DoBindENET
  134. ********************************************************************************/
  135.  
  136. OSStatus DoBind(void)
  137. {
  138.     OSStatus        osstatus;
  139.     TBind            requestInfo;
  140.     TBind            responseInfo;
  141.     UInt32            i;
  142.     
  143.     gAddr.fAddrFamily = AF_8022;
  144.     
  145.     for (i = 0; i < k48BitAddrLength; i++)
  146.         gAddr.fHWAddr[i] = 0x00;
  147.         
  148.     gAddr.fSAP = TESTSAP;
  149.     
  150.     if (TESTSAP == 0xAA)
  151.     {    
  152.         // set SNAP fields;
  153.         
  154.         gAddr.fSNAP[0] = MYSNAP0;        // set these values in the interface file OTLLCTest.h
  155.         gAddr.fSNAP[1] = MYSNAP1;
  156.         gAddr.fSNAP[2] = MYSNAP2;
  157.         gAddr.fSNAP[3] = MYSNAP3;
  158.         gAddr.fSNAP[4] = MYSNAP4;
  159.         
  160.         requestInfo.addr.len = k8022SNAPAddressLength;        
  161.     }
  162.     else
  163.     {
  164.         requestInfo.addr.len = k8022BasicAddressLength;        
  165.     }
  166.  
  167.         
  168.         // finish bind information
  169.     requestInfo.addr.buf = (UInt8 *)&gAddr;
  170.  
  171.     requestInfo.addr.maxlen = 0;            
  172.     requestInfo.qlen = 0;
  173.     
  174.     responseInfo.addr.buf = (UInt8 *)&gAddr;
  175.     responseInfo.addr.len = 0;        
  176.     responseInfo.addr.maxlen = k8022SNAPAddressLength;
  177.     responseInfo.qlen = 0;
  178.     
  179.     
  180.     
  181.     osstatus = OTBind(gEndpoint, &requestInfo, &responseInfo);
  182.     if (osstatus == kOTNoError)
  183.         SetEPBoundFlag(gFlags);
  184.         
  185.     return osstatus;
  186. }
  187.  
  188.  
  189.  
  190. /*******************************************************************************
  191. ** DoAddMulticast
  192. ********************************************************************************/
  193.  
  194. OSStatus DoAddMulticast(EndpointRef ep, unsigned char *mcAddr)
  195. {
  196.     OSStatus    osstatus = noErr;
  197.     TOptMgmt    req;
  198.     UInt8        reqOpt[64];        
  199.     
  200.     req.opt.buf    = reqOpt;
  201.     req.flags    = T_NEGOTIATE;
  202.     
  203.     ((TOption*)reqOpt)->level    = LNK_TPI;
  204.     ((TOption*)reqOpt)->name    = OPT_ADDMCAST;
  205.     ((TOption*)reqOpt)->len        = kOTOptionHeaderSize + k48BitAddrLength;
  206.     ((TOption*)reqOpt)->status    = 0;
  207.     memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
  208.                 
  209.     req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
  210.     req.opt.maxlen = sizeof(reqOpt);
  211.                 
  212.     if ( (osstatus = OTOptionManagement(ep, &req, &req)) != kOTNoError )
  213.         fprintf(stderr, "DoAddMulticast - OptionManagement Returned %d\n", osstatus);
  214.     else
  215.     {
  216.         if (((TOption*)reqOpt)->status != T_SUCCESS)
  217.         
  218.         {
  219.             fprintf(stderr, "DoAddMulticast - failed Status = %d\n", ((TOption*)reqOpt)->status);
  220.             osstatus = -1;
  221.         }
  222.         else
  223.         {
  224.             fprintf(stderr, "DoAddMulticast - was successful\n");
  225.             SetMCastActiveFlag(gFlags);
  226.         }
  227.     }
  228.     return osstatus;
  229. }
  230.  
  231.  
  232. /*******************************************************************************
  233. ** DoRemoveMulticast
  234. ********************************************************************************/
  235.  
  236. OSStatus DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr)
  237. {
  238.     OSStatus    osstatus = noErr;
  239.     TOptMgmt    req;
  240.     UInt8        reqOpt[64];        
  241.     
  242.     req.opt.buf    = reqOpt;
  243.     req.flags    = T_NEGOTIATE;
  244.     
  245.     ((TOption*)reqOpt)->level    = LNK_TPI;
  246.     ((TOption*)reqOpt)->name    = OPT_DELMCAST;
  247.     ((TOption*)reqOpt)->status    = 0;
  248.     ((TOption*)reqOpt)->len        = kOTOptionHeaderSize + k48BitAddrLength;
  249.     memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
  250.                     
  251.     req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
  252.     req.opt.maxlen    = sizeof(reqOpt);
  253.     
  254.     if ( (osstatus = OTOptionManagement(ep, &req, &req)) != kOTNoError )
  255.         fprintf(stderr, "\nDoRemoveMulticast failed - OptionManagement Returned %d.", osstatus);
  256.     else
  257.     { 
  258.         if (((TOption*)reqOpt)->status != T_SUCCESS)
  259.         {
  260.             fprintf(stderr, "nDoRemoveMulticast - failed Status = %d\n", ((TOption*)reqOpt)->status);
  261.             osstatus = -1;
  262.         }
  263.         else
  264.         {
  265.             fprintf(stderr, "nDoRemoveMulticast - was successful\n");
  266.             SetMCastActiveFlag(gFlags);
  267.         }
  268.     }
  269.  
  270.     return osstatus;
  271. }
  272.  
  273. void WriteApplIntro(void)
  274. {
  275.     fprintf(stderr, "\nEthernet 802.2 LLC Test program v1.0\n");
  276.     fprintf(stderr, "\nThis test application sets the system");
  277.     fprintf(stderr, "\ninto send or receive mode.\n");
  278.     fprintf(stderr, "\nThe send portion of this program sets the Ethernet");
  279.     fprintf(stderr, "\ndriver to use a multicast address, then sends 10000");
  280.     fprintf(stderr, "\n- 1500 byte packets out the wire.\n");
  281.     fprintf(stderr, "\nThe receive portion of this program sets the Ethernet");
  282.     fprintf(stderr, "\ndriver to use a multicast address, then waits for the");
  283.     fprintf(stderr, "\n10000 - 1500 byte packets or times out after 30 seconds.\n");
  284.     fprintf(stderr, "\n\nUsing SAP address %d.\n", TESTSAP);
  285.     
  286. }
  287.  
  288. UInt32 GetYesNoOption(void)
  289. {
  290.     UInt32    result;
  291.     char    selection[32];
  292.     Boolean    done;
  293.     
  294.     fprintf(stdout, "\n    Enter Y - To accept option");
  295.     fprintf(stdout, "\n    Enter N - To decline option");
  296.     fprintf(stdout, "\n    Enter Q - To quit");
  297.     fprintf(stdout, "\nYour selection -> ");
  298.     fflush(stdout);
  299.     done = false;
  300.  
  301.     do
  302.     {
  303.         scanf("%s", selection);
  304.         switch (selection[0])
  305.         {
  306.             case 'y':
  307.             case 'Y':
  308.                 result = kAcceptOption;
  309.                 done = true;
  310.                 break;
  311.             
  312.             case 'n':
  313.             case 'N':
  314.                 result = kDeclineOption;
  315.                 done = true;
  316.                 break;
  317.  
  318.             case 'q':
  319.             case 'Q':
  320.                 result = kQuitTest;
  321.                 done = true;
  322.                 break;
  323.                 
  324.             default:
  325.                 fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  326.                 fflush(stdout);
  327.                 break;
  328.  
  329.         }
  330.     } while (!done);
  331.     
  332.     fflush (stdout);
  333.     return result;
  334. }
  335.  
  336.  
  337. UInt32 GetUserOption(void)
  338. {
  339.     UInt32    result;
  340.     char    selection[32];
  341.     Boolean    done;
  342.     
  343.     fprintf(stdout, "\nSelect the type of test to run");
  344.     fprintf(stdout, "\nMake sure that the receive program is already launched");
  345.     fprintf(stdout, "\n    Enter S - Send test packets");
  346.     fprintf(stdout, "\n    Enter R - Receive test packets");
  347.     fprintf(stdout, "\n    Enter q - quit");
  348.     fprintf(stdout, "\nYour selection -> ");
  349.     fflush(stdout);
  350.     done = false;
  351.  
  352.     do
  353.     {
  354.         scanf("%s", selection);
  355.         switch (selection[0])
  356.         {
  357.             case 'r':
  358.             case 'R':
  359.                 result = kReceiveTest;
  360.                 done = true;
  361.                 break;
  362.             
  363.             case 's':
  364.             case 'S':
  365.                 result = kSendTest;
  366.                 done = true;
  367.                 break;
  368.  
  369.             case 'q':
  370.             case 'Q':
  371.                 result = kQuitTest;
  372.                 done = true;
  373.                 break;
  374.                 
  375.             default:
  376.                 fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  377.                 fflush(stdout);
  378.                 break;
  379.  
  380.         }
  381.     } while (!done);
  382.     
  383.     fflush (stdout);
  384.     return result;
  385. }
  386.  
  387. /*
  388.     CanDoMDATAMode gets the endpoint info and checks whether the T_CAN_SUPPORT_MDATA bit is
  389.     set in the endpoint info flag field and returns true if so, false otherwise.
  390. */
  391. Boolean CanDoMDATAMode(EndpointRef ep)
  392. {
  393.     TEndpointInfo    info;
  394.     OSStatus        err;
  395.     Boolean            result;
  396.     
  397.     err = OTGetEndpointInfo(ep, &info);
  398.     if (err != kOTNoError)
  399.         result = false;
  400.     else if (info.flags & T_CAN_SUPPORT_MDATA)
  401.         result = true;        // this also means that the src addr info is in the info record
  402.     else
  403.         result = false;
  404.  
  405.     return result;
  406. }
  407.  
  408.  
  409. void DoOTLLCWriteTest(void)
  410. {
  411.     OSStatus    osstatus;
  412.     UInt32        numMemErrs, last250;
  413.     UInt32        lastFlowErrPacketNum;
  414.     UInt32        timer;
  415.     time_t        t1, t2, t3;
  416.     UInt16        rawModeOffset = 0;
  417.     Boolean        callDoIdle;
  418.     
  419.     
  420.     osstatus = DoBind();
  421.     
  422.     OTMemzero(&gPacket, sizeof(gPacket));        // zero out the global packet buffer structure
  423.  
  424.     if (TstUseAckSendsFlag(gFlags))
  425.     {
  426.         osstatus = OTAckSends(gEndpoint);
  427.         if (osstatus != kOTNoError)
  428.         {
  429.             fprintf (stdout, "\n Error turning AckSends on - error %ld", osstatus);
  430.             ClrUseAckSendsFlag(gFlags);
  431.             gNumFore = gNumBack = 0;
  432.         }
  433.     }
  434.  
  435.     if (TstUseRawModeFlag(gFlags))
  436.     {
  437.         if (CanDoMDATAMode(gEndpoint) && (DATASIZE <= 1500))
  438.         {
  439.             osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn, &gTemplateType);
  440.             if (osstatus == kOTNoError)
  441.             {
  442.                 SetRawModeFlag(gFlags);
  443.                     /* if rawmode is on then we want to offset the data
  444.                     * an additional 17 bytes and set the header info
  445.                     * ourselves.
  446.                     * note that 17 bytes constitutes the 6 byte dAddr, 6 byte sAddr
  447.                     * 2 byte length field, 1 byte ssap, 1 byte dsap and 1 byte control byte
  448.                     
  449.                     * Note that even if the DSAP is not 0xAA, we go ahead and stuff the 5 bytes
  450.                     * following the control byte, with whatever SNAP values have been defined.
  451.                     */
  452.                 gPacket.rawModeOffset = 17;
  453.                     // check is we are doing SNAP
  454.                 if (TESTSAP == 0xAA)
  455.                     gPacket.rawModeOffset += 5;
  456.                 fprintf (stdout, "\n raw mode option enabled");
  457.             }
  458.             else
  459.             {
  460.                     // if the option failed, then we don't use it'
  461.                 fprintf (stdout, "\nError negotiating raw mode option");
  462.                     // reset the status result.
  463.                 osstatus = kOTNoError;
  464.             }
  465.         }
  466.         else
  467.             fprintf (stdout, "\nYou need a later version of OT which supports the MDataMode option");
  468.     }
  469.  
  470. #if __ASYNCSEND__
  471.     if (osstatus == kOTNoError)
  472.     {
  473.         osstatus = OTSetAsynchronous(gEndpoint);
  474.         if (osstatus != kOTNoError) 
  475.         {
  476.             fprintf(stderr, "\n\nError making endpoint asynchronous!");
  477.             fprintf(stderr, "\nOTSetAsynchronous returned %d\n", osstatus);
  478.         }
  479.     }    // now ready to handle async events
  480. #endif        
  481.  
  482.     if (osstatus == kOTNoError)
  483.     {
  484.             // set up the first 18 bytes past the control byte for non SNAP LLC endpoint or
  485.             // past the SNAP header for a SNAP endpoint, so that we can recognize it 
  486.         OTStrCopy((char*)&gPacket.data[gPacket.rawModeOffset], "begin data section");
  487.  
  488.             // set up some specific bytes in the data buffer that begins at the same point
  489.             // relative to the LLC or SNAP header
  490.         gPacket.data[DATAOFFSET     + gPacket.rawModeOffset] = 0;
  491.         gPacket.data[DATAOFFSET + 1 + gPacket.rawModeOffset] = 0;
  492.         OTStrCopy((char*)&gPacket.data[DATAOFFSET+2 + gPacket.rawModeOffset], "end of data section");
  493.         
  494.         gPacket.unitdata.udata.buf = (UInt8*)gPacket.data;
  495.     
  496.         if (TstRawModeFlag(gFlags))
  497.             gPacket.unitdata.udata.len = DATASIZE + 14;
  498.         else
  499.         {
  500.                 // the DATASIZE setting represents the total size of the packet
  501.                 // following the ethernet header.  If we are not doing a rawmode send
  502.                 // then we need to account for the fact that part of the data area
  503.                 // will be used by OT to place the SSAP, DSAP, and Control byte.  If
  504.                 // we are sending a SNAP packet, then we have to account for the 5
  505.                 // additional bytes of the SNAP header.  Otherwise if the unidata.data.len
  506.                 // field were set to the full size of 1500, the packet would not be sent
  507.                 // since OT would think it was trying to send a 1503 or 1508 byte 
  508.                 // ethernet packet (not including the ethernet header).
  509.                 
  510.                 // By doing this, we can process the packet using either a raw data or
  511.                 // regular ethernet endpoint as the receiver.
  512.                 
  513.             if (TESTSAP == 0xAA)
  514.                 gPacket.unitdata.udata.len = DATASIZE - 8;
  515.             else
  516.                 gPacket.unitdata.udata.len = DATASIZE - 3;
  517.         }
  518.             
  519.         gPacket.unitdata.opt.len = 0;
  520.         gPacket.unitdata.opt.buf = NULL;
  521.  
  522.         if (TstRawModeFlag(gFlags) == false)
  523.         {
  524.                 // set up the destination addresss
  525.             gPacket.dAddr.fAddrFamily = AF_8022;
  526.             
  527.             gPacket.dAddr.fHWAddr[0] = MCASTADDR0;
  528.             gPacket.dAddr.fHWAddr[1] = MCASTADDR1;
  529.             gPacket.dAddr.fHWAddr[2] = MCASTADDR2;
  530.             gPacket.dAddr.fHWAddr[3] = MCASTADDR3;
  531.             gPacket.dAddr.fHWAddr[4] = MCASTADDR4;
  532.             gPacket.dAddr.fHWAddr[5] = MCASTADDR5;
  533.                 
  534.             gPacket.dAddr.fSAP = TESTSAP;
  535.             
  536.             gPacket.unitdata.addr.buf = (UInt8*)&gPacket.dAddr;
  537.             if (TESTSAP == 0xAA)
  538.             {
  539.                 gPacket.dAddr.fSNAP[0] = MYSNAP0;
  540.                 gPacket.dAddr.fSNAP[1] = MYSNAP1;
  541.                 gPacket.dAddr.fSNAP[2] = MYSNAP2;
  542.                 gPacket.dAddr.fSNAP[3] = MYSNAP3;
  543.                 gPacket.dAddr.fSNAP[4] = MYSNAP4;
  544.         
  545.                 gPacket.unitdata.addr.len = k8022SNAPAddressLength;
  546.             }
  547.             else
  548.                 gPacket.unitdata.addr.len = k8022BasicAddressLength;
  549.  
  550.         }
  551.         else
  552.         {
  553.                 // set up for a rawmode send data call
  554.             gPacket.data[0] = MCASTADDR0;
  555.             gPacket.data[1] = MCASTADDR1;
  556.             gPacket.data[2] = MCASTADDR2;
  557.             gPacket.data[3] = MCASTADDR3;
  558.             gPacket.data[4] = MCASTADDR4;
  559.             gPacket.data[5] = MCASTADDR5;
  560.                 // set the packet len field
  561.             gPacket.data[12] = DATASIZE >> 8;
  562.             gPacket.data[13] = DATASIZE & 0xFF;
  563.                 // set the dsap, ssap, and control byte fields.
  564.             gPacket.data[14] = TESTSAP;            // set DSAP
  565.             gPacket.data[15] = TESTSAP;            // set SSAP
  566.             gPacket.data[16] = 0x03;            // set control byte
  567.             
  568.             if (TESTSAP == 0xAA)
  569.             {
  570.                     // set up the SNAP Addr
  571.                 gPacket.data[17] = MYSNAP0;
  572.                 gPacket.data[18] = MYSNAP1;
  573.                 gPacket.data[19] = MYSNAP2;
  574.                 gPacket.data[20] = MYSNAP3;
  575.                 gPacket.data[21] = MYSNAP4;
  576.             }
  577.         
  578.             gPacket.unitdata.addr.buf = nil;    
  579.                                         // don't want to set the destination address since we've already 
  580.                                         // done so in the data
  581.                                         
  582.                                         // the following line is required for OT 1.2 and greater
  583.                                         // where there is a bug with how OT deals with mentat template
  584.                                         // based drivers, such that in rawmode, the total packet size - 
  585.                                         // header + data is limited to 1500 bytes.  By using the following
  586.                                         // line, OT will not check for this limitation and will go ahead
  587.                                         // and send an MDATA message.
  588.  
  589.             gPacket.unitdata.addr.len = 0xFFFFFFFFL;        
  590.                                         // magic constant for M_DATA mode
  591.                         
  592.         }
  593.  
  594.  
  595.         ClrFlowClrFlag(gFlags);        // clear the flag that indicates that a T_GODATA event occurred
  596.                                     // we do this because a race condition might occur when we make the
  597.                                     // the OTSndUData call, a flowerr may occur, but get cleared by the time
  598.                                     // we actually check the osstatus field
  599.  
  600.         fprintf (stdout, "\n starting write of %ld llc packets of %ld bytes\n", (long)SENDCOUNT, (long)DATASIZE);
  601.         fflush(stdout);
  602.         t1 = clock ();
  603.         
  604.         gDone = false;
  605.         gPacket.i = 0;
  606.         numMemErrs = last250 = 0;
  607.         lastFlowErrPacketNum = 0;
  608.         timer = 0;
  609.         callDoIdle = false;
  610.         
  611.             // set the flag that will tell us to send a packet at system task time so that
  612.             // we can send the initial packet
  613.         SetSysTaskSendFlag(gFlags);
  614.         
  615.         while (!gDone && !gAbort)
  616.         {            
  617.             if (TstSysTaskSendFlag(gFlags))
  618.             {
  619.                 if (DoSendPacket(gEndpoint) == true)
  620.                 {
  621.                     gNumFore++;
  622.                 }
  623.             }
  624.  
  625.             if (gNumMemErrs)
  626.             {
  627.                 if (numMemErrs != gNumMemErrs)
  628.                 {
  629.                     numMemErrs = gNumMemErrs;
  630.  
  631.                     fprintf(stderr, "\nkENOMEMErr %ld.", gPacket.i);
  632.                     callDoIdle = true;
  633.                 }
  634.             }
  635.                         
  636. #if 0    // the following code really affect the performance of this tool
  637.         // and can consume over 95 percent of the processing time of this tool
  638.         // on a fast system.
  639.             n = gPacket.i / 250;
  640.             if (n > last250)
  641.             {
  642.                 fprintf(stderr, "%d ", n * 250);
  643.                 fflush(stderr);
  644.                 last250 = n;
  645.  
  646.             }
  647. #endif
  648.                         
  649.             timer++;
  650.             if (timer > gTimerThreshold)
  651.             {
  652.                 callDoIdle = true;
  653.             }
  654.                     
  655.             if (gPacket.lastFlowErrPacketNum != 0)
  656.             {
  657.                 if (lastFlowErrPacketNum != gPacket.lastFlowErrPacketNum)
  658.                 {
  659.                     fprintf(stderr, "\nflow error occurred while sending packet %d.", gPacket.lastFlowErrPacketNum);
  660.                     lastFlowErrPacketNum = gPacket.lastFlowErrPacketNum;
  661.                 }
  662.             }
  663.             
  664.                 // check if we are flow controlled or if it's time to call WNE and call it.
  665.             if ((callDoIdle == true) || TstFlowErrFlag(gFlags))
  666.             {
  667.                 CallWNE();
  668.                 callDoIdle = false;
  669.                 timer = 0;
  670.             }
  671.             
  672.         }    // end while loop sending data
  673.  
  674.         fflush(stderr);
  675.                 
  676.         t2 = clock();
  677.         t3 = t2 - t1;
  678.         fprintf (stdout, "\nCompleted sending %ld llc packets.", (long)gPacket.i);
  679.         fprintf (stdout, "\nTime start = %ld, time end = %ld, time taken %ld seconds.",
  680.                      t1, t2, (long)t3/CLOCKS_PER_SEC);
  681.         fprintf (stdout, "\nPackets per second = %ld, bytes/second = %ld.",
  682.                      ((long)gPacket.i*CLOCKS_PER_SEC)/t3, ((long)gPacket.i*DATASIZE*CLOCKS_PER_SEC)/t3);
  683.         
  684.         fprintf (stdout, "\n Press the mouse to unbind the endpoint");
  685.         
  686.         if (TstUseAckSendsFlag(gFlags) == true)
  687.         {
  688.             fprintf (stdout, "\nThe number of packets sent from the while loop - %ld", gNumFore);
  689.             fprintf (stdout, "\nThe number of packets sent from the handler - %ld", gNumBack);
  690.         }
  691.         
  692.         fflush(stdout);
  693.  
  694.         while (!Button())
  695.             MyIdle();
  696.                         
  697.         
  698.     }    // end if bind successful
  699.  
  700. #if __ASYNCSEND__    
  701.     if (TstEPBoundFlag(gFlags))
  702.     {
  703.         OTSetSynchronous(gEndpoint);
  704.         OTUnbind(gEndpoint);
  705.     }
  706. #endif
  707.  
  708. }
  709.  
  710. Boolean DoSendPacket(EndpointRef ep)
  711. {
  712.     OSStatus        osstatus;
  713.     Boolean            didEnter;
  714.  
  715.         // check to see if we have already entered this function.
  716.         // we only want to enter into it once whether at system task time or from the
  717.         // handler
  718.     if (OTAtomicSetBit(&gFlag1, kInSendPacketBit))
  719.         return false;
  720.     
  721.         // call OTenterNotifier so that the notifier is not entered while we are in the following
  722.         // section of code. In this way we protect ourselves from race conditions that could 
  723.         // happen - for example if a flowErr occured, but was cleared before we set the flowErr
  724.         // flag, this would be a problem since we would never receive notification that flow
  725.         // control was lifted.
  726.         
  727.     didEnter = OTEnterNotifier(ep);
  728.         
  729.     if (gDone == false)
  730.     {
  731.             // we already assume that the packet is ready to send
  732.         osstatus = OTSndUData(gEndpoint, &gPacket.unitdata);
  733.     }
  734.     
  735.     switch (osstatus)
  736.     {
  737.         case kENOMEMErr:
  738.             gNumMemErrs++;
  739.             break;
  740.             
  741.         case kOTNoError:    // send was successful
  742.             gPacket.i++;
  743.                             
  744.             if (gPacket.i >= SENDCOUNT)
  745.                 gDone = true;
  746.             else
  747.             {
  748.                     // increment the counter in the packet
  749.                 gPacket.data[DATAOFFSET+0+gPacket.rawModeOffset] = gPacket.i >> 8;
  750.                 gPacket.data[DATAOFFSET+1+gPacket.rawModeOffset] = gPacket.i;
  751.                     
  752.             }                
  753.             break;
  754.         
  755.         case kOTFlowErr:
  756.             SetFlowErrFlag(gFlags);            // a T_GODATA did not just come in
  757.             ClrSysTaskSendFlag(gFlags);        // clear the flag that we check to send a packet
  758.             gPacket.lastFlowErrPacketNum = gPacket.i;    // save the packet number on which the flow err occured
  759.             break;
  760.         
  761.         default:
  762.             DoValueBreak(osstatus, "Unknown error occurred in DoSendPacket #;");
  763.             gDone = true;
  764.             ClrSysTaskSendFlag(gFlags);
  765.             break;
  766.     }
  767.     
  768.     if (didEnter == true)
  769.          OTLeaveNotifier(ep);
  770.     
  771.     OTAtomicClearBit(&gFlag1, kInSendPacketBit);
  772.     return true;
  773. }
  774.         
  775. void DoOTLLCReadTest(void)
  776. {
  777.     OSStatus    osstatus;
  778.     long        timer;
  779.     
  780.     gBuffer = (UInt8*)NewPtr(DATASIZE + 2* DATASLOP);    // allocate the data buffer + some slop
  781.     if (gBuffer)
  782.         osstatus = DoBind();
  783.     else
  784.     {
  785.         osstatus = memFullErr;
  786.         return;
  787.     }
  788.  
  789.     gBackToBackPackets = 0;
  790.     gInOrder = 0;
  791.     gOutOfOrder = 0;
  792.     gCounter = 0;
  793.     gPacketsRead = 0;
  794.     gNumDataEvents = 0;
  795.     gReadErrors = 0;
  796.     gNumMemErrs = 0;
  797.     gDone = false;
  798.     
  799.     if (osstatus == kOTNoError)
  800.     {
  801.         osstatus = DoAddMulticast(gEndpoint, gmcAddr);
  802.     }
  803.     
  804.     if (osstatus == kOTNoError)
  805.     {
  806.         if (TstUseRawModeFlag(gFlags))
  807.         {
  808.             osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn, &gTemplateType);
  809.             if (osstatus == kOTNoError)
  810.             {
  811.                 SetRawModeFlag(gFlags);
  812.             }
  813.             else
  814.             {
  815.                     // if the option failed, then we don't use it'
  816.                 fprintf (stdout, "\nError negotiating raw mode option");
  817.                     // reset the status result.
  818.                 osstatus = kOTNoError;
  819.             }
  820.         }
  821.     }
  822.     
  823. #ifdef __ASYNCSEND__
  824.     if (osstatus == kOTNoError)
  825.     {
  826.         osstatus = OTSetAsynchronous(gEndpoint);
  827.         if (osstatus != kOTNoError) 
  828.         {
  829.             fprintf(stderr, "\n\nError making endpoint asynchronous!");
  830.             fprintf(stderr, "\nOTSetAsynchronous returned %d\n", osstatus);
  831.         }
  832.     }    // now ready to handle async events
  833. #endif
  834.         
  835.     if (osstatus == kOTNoError)
  836.     {
  837.         gAbort = false;
  838.         SetWantDataFlag(gFlags);
  839.                 
  840.         fprintf (stdout, "\nStarting Read test - will terminate in %d seconds", TIMEOUT);
  841.         fprintf (stdout, "\nor as soon as the trigger packet is received.");
  842.         fprintf (stdout, "\nYou may use Command-Q to quit the program entirely.");
  843.         fprintf (stdout, "\nYou may also use Command-A to terminate this test.\n");
  844.         fprintf (stdout, "\nStarting Read");
  845.         fflush(stdout);
  846.         
  847.         timer = TickCount() + TIMEOUT * 60;
  848.             // loop until timer is less than TickCount or until the endtime value gets set
  849.         
  850.         while ((timer > TickCount()) && (gDone == false) && (gAbort == false))
  851.         {
  852.                 // allow the user to exit the timer loop by 
  853.             CallWNE();
  854.         }
  855.  
  856.         
  857.         
  858.     }
  859.     
  860.     OTSetSynchronous(gEndpoint);
  861.         
  862.     if (TstMCastActiveFlag(gFlags))
  863.         DoRemoveMulticast(gEndpoint, gmcAddr);
  864.         
  865.     
  866.     if (osstatus == kOTNoError)
  867.     {
  868.         fprintf (stdout, "\n\nBufferReadCount = %ld", gPacketsRead);
  869.         fprintf (stdout, "\nInOrder = %ld\n", gInOrder);
  870.         fprintf (stdout, "\nOutofOrder = %ld\n", gOutOfOrder);
  871.         fprintf (stdout, "\nlast packet read was = %ld\n", gCounter);
  872.         fprintf (stdout, "\nNumber of data events was = %ld\n", gNumDataEvents);
  873.         fprintf (stdout, "\nNumber of read errors was = %ld\n", gReadErrors);
  874.         fprintf (stdout, "\nNumber of back to back packets was = %ld\n", gBackToBackPackets);
  875.         fflush(stdout);
  876.     }
  877.  
  878.     if (TstEPBoundFlag(gFlags))
  879.         OTUnbind(gEndpoint);
  880.  
  881.     if (gBuffer)
  882.         DisposePtr((Ptr)gBuffer);
  883.     
  884. }
  885.  
  886. OSStatus DoReadPacket(EndpointRef ep, UInt8 *mainBuffer)
  887. {
  888.     TUnitData    unitdata;
  889.     struct T8022Address    dAddr;
  890.     OTFlags        otFlags;
  891.     OSStatus    result;
  892.     
  893.     unitdata.addr.maxlen = sizeof(dAddr);
  894.     unitdata.addr.buf = (UInt8*)&dAddr;
  895.     unitdata.udata.buf = mainBuffer;
  896.     unitdata.udata.maxlen = DATASIZE + DATASLOP;
  897.     unitdata.opt.maxlen = 0;
  898.     
  899.     result = OTRcvUData(ep, &unitdata, &otFlags);
  900.     return result;
  901. }
  902.  
  903. pascal void LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie)
  904. {
  905.     #pragma unused(ref,cookie)
  906.     OSStatus    osstatus;
  907.     UInt8        *bufferToUse;
  908.     UInt32        lcounter, offset;
  909.     Boolean        firstTimeFlag;
  910.     
  911.     gstatus = result;
  912.     switch (event)
  913.     {
  914.         case T_MEMORYRELEASED:
  915.             if (DoSendPacket(gEndpoint) == false)
  916.                 SetSysTaskSendFlag(gFlags);
  917.             else
  918.             {
  919.                 ClrSysTaskSendFlag(gFlags);
  920.                 gNumBack++;
  921.             }
  922.             break;
  923.  
  924.         case T_OPTMGMTCOMPLETE:
  925.             ClrWaitOptMgmtFlag(gFlags);
  926.             break;
  927.             
  928.         case T_BINDCOMPLETE:
  929.             ClrStillBindFlag(gFlags);
  930.             break;
  931.         
  932.         case T_UNBINDCOMPLETE:
  933.             break;
  934.         
  935.         case T_GODATA:
  936.             SetFlowClrFlag(gFlags);    // indicate that the flow data problem has now cleared.
  937.             SetSysTaskSendFlag(gFlags);
  938.             break;
  939.         
  940.         case T_DATA:
  941.             gNumDataEvents++;
  942.             if (TstWantDataFlag(gFlags))
  943.                 bufferToUse = gBuffer;
  944.             else
  945.                 bufferToUse = gDummyBuffer;
  946.                 
  947.                 // initialize variables as we enter while loop
  948.             osstatus = kOTNoError;
  949.             firstTimeFlag = true;
  950.             
  951.             while ((osstatus == kOTNoError) && (!gDone))
  952.             {
  953.                 osstatus = DoReadPacket(gEndpoint, bufferToUse);
  954.                 
  955.                 if (firstTimeFlag == true)    
  956.                         // this is the first time through this loop 
  957.                         // for this call to the handler
  958.                     firstTimeFlag = false;
  959.                 else
  960.                         // increment the counter to indicate that there was a packet to
  961.                         // handle after reading the previous packet
  962.                     gBackToBackPackets++;
  963.                     
  964.                 if (osstatus != kOTNoDataErr)
  965.                 {
  966.                     if (osstatus < 0)
  967.                         gReadErrors++;
  968.                     else
  969.                         gPacketsRead++;
  970.                 }
  971.                     
  972.                 if (TstWantDataFlag(gFlags) && (osstatus == kOTNoError))
  973.                 {
  974.                     if (TstRawModeFlag(gFlags))
  975.                     {
  976.                             // if rawmode is on then we want to account for
  977.                             // the additional 17 bytes which will be at the
  978.                             // beginning of the packet.
  979.                         offset = 17;
  980.                         if (TESTSAP == 0xAA)
  981.                         {
  982.                             offset += 5;        // account for the SNAP header
  983.                         }
  984.                         
  985.                             // check if the template is a mentat template and 
  986.                             // adjust the offset to account for the additional
  987.                             // bytes that the template prepends to the ethernet
  988.                             // packet.
  989.                         if (gTemplateType == kMentatTemplate)
  990.                             offset += sizeof(dl_recv_status_t);
  991.                     }
  992.                     else
  993.                         offset = 0;
  994.                     
  995.                     lcounter = gBuffer[DATAOFFSET + offset +0] << 8;
  996.                     lcounter |= gBuffer[DATAOFFSET + offset +1];
  997.                     if (lcounter >= TRIGGEREND)
  998.                     {
  999.                         gDone = true;        // we can bail now.
  1000.                     }
  1001.                     else
  1002.                     {
  1003.                         if (lcounter == gCounter)
  1004.                             gInOrder++;
  1005.                         else
  1006.                             gOutOfOrder++;
  1007.                         
  1008.                         gCounter = lcounter + 1;    // prepare gCounter for next incoming packet to compare
  1009.                     }
  1010.                 }
  1011.             }
  1012.             break;
  1013.             
  1014.         default:
  1015.             DoValueBreak(event, "Unknown event  occurred #           ;g");
  1016.             break;
  1017.             
  1018.         
  1019.     }    /* end switch on event */
  1020. }
  1021.  
  1022. /*******************************************************************************
  1023. ** CallWNE is implemented to call WaitNextEvent to check for the Command-Q key
  1024. ** sequence.  When this happens, then the gdone flag is set to true
  1025. ********************************************************************************/
  1026.  
  1027. void CallWNE(void)
  1028. {
  1029.     EventRecord     event;
  1030.     char            key;
  1031.     
  1032.     if (!WaitNextEvent(everyEvent, &event, 15, nil))
  1033.         event.what = nullEvent;
  1034.             
  1035.     switch (event.what)
  1036.     {
  1037.  
  1038.  
  1039.         case nullEvent:
  1040.         case mouseDown:
  1041.         case activateEvt:
  1042.         case updateEvt:
  1043.         case kHighLevelEvent:
  1044.         case osEvt:
  1045.         case diskEvt:
  1046.             break;
  1047.  
  1048.         case autoKey:
  1049.         case keyDown:
  1050.             key = event.message & charCodeMask;
  1051.             switch (key)
  1052.             {
  1053.                 case 'q':
  1054.                 case 'Q':
  1055.                     if (event.modifiers & cmdKey)
  1056.                     gDone = true;
  1057.                     break;
  1058.                     
  1059.                 case 'a':
  1060.                 case 'A':
  1061.                     if (event.modifiers & cmdKey)
  1062.                     gAbort = true;
  1063.                     break;
  1064.             }
  1065.             break;
  1066.  
  1067.     }
  1068.     
  1069. }
  1070.  
  1071. void MyIdle(void)
  1072. {
  1073.     EventRecord        event;
  1074.     OSErr            err;
  1075.     
  1076.     err = WaitNextEvent(everyEvent, &event, 15 + gNumMemErrs * 5, nil);
  1077. }
  1078.  
  1079. void main (void)
  1080. {
  1081.     OSStatus    osstatus = noErr;
  1082.     UInt32        selection;
  1083.     char        drvrname[64];
  1084.     Boolean        done = false;
  1085.     
  1086.     WriteApplIntro();
  1087.     gFlags = 0;
  1088.     if (osstatus = InitOpenTransport())
  1089.     {
  1090.         fprintf(stderr, "\n\nOpen Transport is not installed!\n");
  1091.         fprintf(stderr, "\nBye Bye.\n");
  1092.     }
  1093.     else
  1094.     {
  1095.         SetOTActiveFlag(gFlags);    // indicate that OT is active
  1096.  
  1097.         gDummyBuffer = (UInt8*)NewPtr(DATASIZE + 2 * DATASLOP);
  1098.         if (gDummyBuffer == NULL)
  1099.             osstatus = memFullErr;
  1100.     }
  1101.     
  1102.     PrintAppleTalkPortName();
  1103.  
  1104.     while (done == false)
  1105.     {
  1106.         osstatus = OTSetMemoryLimits(10240000, 0);
  1107.         if (osstatus != kOTNoError)
  1108.         {
  1109.             fprintf(stderr, "\n OTSetMemoryLimits returned %d\n", osstatus);
  1110.             osstatus = kOTNoError;
  1111.         }
  1112.                 
  1113.         if (osstatus != kOTNoError)
  1114.         {
  1115.             done = true;
  1116.             break;
  1117.         }
  1118.         
  1119.         ListEnetDrivers();
  1120.         GetDriverName(drvrname);
  1121.         
  1122.             // open the default ethernet endpoint
  1123.         gEndpoint = OTOpenEndpoint(OTCreateConfiguration(drvrname), (OTOpenFlags)NULL, NULL, &osstatus);
  1124.         if (osstatus != kOTNoError)
  1125.         {
  1126.             fprintf(stderr, "\n\nError opening Ethernet endpoint!");
  1127.             fprintf(stderr, "\nOTOpenEndpoint returned %d\n", osstatus);
  1128.             fprintf(stderr, "\nBye Bye.\n");
  1129.             done = true;
  1130.         }
  1131.         else
  1132.             SetEPActiveFlag(gFlags);    // indicate that the endpoint is opened
  1133.     
  1134.         if (osstatus == kOTNoError)
  1135.         {
  1136.             osstatus = OTInstallNotifier(gEndpoint, LLCEventHandler, NULL);
  1137.             if (osstatus != kOTNoError)
  1138.             {
  1139.                 fprintf(stderr, "\n\nError installing notifier!");
  1140.                 fprintf(stderr, "\nOTInstallNotifier returned %d\n", osstatus);
  1141.             }
  1142.         }    // now ready to handle async events
  1143.     
  1144.         if (osstatus == kOTNoError)
  1145.         {
  1146.                 // ask whether to use the rawmode option or not
  1147.             fprintf(stdout, "\nDo you want to use the raw mode option?");
  1148.             selection = GetYesNoOption();
  1149.             if (selection == kQuitTest)
  1150.             {
  1151.                 fprintf(stderr, "\n\nBye-Bye!");
  1152.                 osstatus = -1;
  1153.                 done = true;
  1154.             }
  1155.             else if (selection == kAcceptOption)
  1156.                 SetUseRawModeFlag(gFlags);
  1157.             else if (selection == kDeclineOption)
  1158.                 ClrUseRawModeFlag(gFlags);
  1159.             
  1160.         }
  1161.     
  1162.         if (osstatus == kOTNoError)
  1163.         {
  1164.                 
  1165.                 // what does the user want to do
  1166.             selection = GetUserOption();
  1167.             
  1168.             switch (selection)
  1169.             {
  1170.                 case kSendTest:
  1171.                     fprintf(stdout, "\nDo you want to turn on AckSends?");
  1172.                     selection = GetYesNoOption();
  1173.                     if (selection == kQuitTest)
  1174.                     {
  1175.                         fprintf(stderr, "\n\nBye-Bye!");
  1176.                         done = true;
  1177.                         break;
  1178.                     }
  1179.                     else if (selection == kAcceptOption)
  1180.                     {
  1181.                         SetUseAckSendsFlag(gFlags);
  1182.                     }
  1183.                     else if (selection == kDeclineOption)
  1184.                     {
  1185.                         ClrUseAckSendsFlag(gFlags);
  1186.                         SetTimerThreshold();
  1187.                     }
  1188.  
  1189.                         // pause until the user clicks the mouse button
  1190.                     fprintf(stderr, "Click Mouse to start test\n");
  1191.                     while (!Button());
  1192.                     DoOTLLCWriteTest();
  1193.                     break;
  1194.                 
  1195.                 case kReceiveTest:
  1196.                         // pause until the user clicks the mouse button
  1197.                     fprintf(stderr, "\n\nClick Mouse to start test\n");
  1198.                     while (!Button());
  1199.  
  1200.                     DoOTLLCReadTest();
  1201.                     break;
  1202.                 
  1203.                 case kQuitTest:
  1204.                 default:
  1205.                     fprintf(stderr, "\n\nBye-Bye!");
  1206.                     done = true;
  1207.                     break;
  1208.             }
  1209.         }
  1210.             
  1211.         if (TstEPActiveFlag(gFlags))
  1212.         {
  1213.                 // force endpoint to be synchronous
  1214.             OTSetSynchronous(gEndpoint);
  1215.             OTCloseProvider(gEndpoint);
  1216.         }
  1217.         
  1218.         if (done == false)
  1219.         {
  1220.             fprintf(stdout, "\n\nDo you want to repeat the test?");
  1221.             selection = GetYesNoOption();
  1222.  
  1223.             if (selection != kAcceptOption)
  1224.                 done = true;
  1225.         }
  1226.     }
  1227.     
  1228.     if (gDummyBuffer)
  1229.         DisposePtr((Ptr)gDummyBuffer);
  1230.     
  1231.     OTSetMemoryLimits(0, 0);
  1232.         
  1233.     if (TstOTActiveFlag(gFlags))
  1234.         CloseOpenTransport();
  1235.     
  1236.     fprintf(stderr, "\nProgram ended");
  1237. }
  1238.  
  1239. void DoValueBreak(long value, const char* message)
  1240. {
  1241.     static short    sDoErrorBreak = 0;
  1242.  
  1243.     {
  1244.         Str255    s,
  1245.                 n = "\p";
  1246.  
  1247.         s[0] = strlen(message);
  1248.         BlockMoveData(message,&s[1],s[0]);
  1249.         if (value < 0)
  1250.         {
  1251.             s[0] += 1;
  1252.             s[s[0]] = '-';
  1253.             value = -value;
  1254.         }
  1255.         while (value)
  1256.         {
  1257.             if (n[0])
  1258.                 BlockMoveData(&n[1],&n[2],n[0]);
  1259.             n[0]++;
  1260.             n[1] = 48 + (value % 10);
  1261.             value /= 10;
  1262.         }
  1263.         BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1264.         s[0] += n[0];
  1265.  
  1266.         sDoErrorBreak++;
  1267.         {
  1268.             short    cnt = sDoErrorBreak;
  1269.  
  1270.             s[0]++;
  1271.             s[s[0]] = ',';
  1272.             s[0]++;
  1273.             s[s[0]] = ' ';
  1274.             n[0] = 0;
  1275.             while (cnt)
  1276.             {
  1277.                 if (n[0])
  1278.                     BlockMoveData(&n[1],&n[2],n[0]);
  1279.                 n[0]++;
  1280.                 n[1] = 48 + (cnt % 10);
  1281.                 cnt /= 10;
  1282.             }
  1283.             BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1284.             s[0] += n[0];
  1285.         }
  1286.         DebugStr(s);
  1287.     }
  1288. }
  1289.  
  1290. void GetDriverName(char *name)
  1291. {
  1292.         fprintf(stdout, "\nEnter the driver name to use");
  1293.         fprintf(stdout, "\nEnter an invalid driver name to quit");
  1294.         fprintf(stdout, "\n : ");
  1295.         while (true)
  1296.         {
  1297.             gets(name);
  1298.             if (*name != 0)
  1299.                 break;
  1300.         }
  1301. }
  1302.  
  1303. void SetTimerThreshold(void)
  1304. {
  1305.     char    chr, str[256];
  1306.     size_t    len, i;
  1307.     Boolean    done = false;
  1308.     
  1309.     while (done == false)
  1310.     {
  1311.         fprintf(stdout, "\n Enter the timer threshold");
  1312.         fprintf(stdout, "\n This is the number of times that the write loop loops before calling");
  1313.         fprintf(stdout, "\n WaitNextEvent. Enter a value of 10000 to never call WNE.");
  1314.         fprintf(stdout, "\n Enter a value of 100 to call WNE every 100 packets.\n");
  1315.         while (true)
  1316.         {
  1317.             gets(str);
  1318.             if (*str != 0)
  1319.                 break;
  1320.         }
  1321.         
  1322.         gTimerThreshold = 0;
  1323.         len = strlen(str);
  1324.         
  1325.         for (i = 0; i < len; i++)
  1326.         {
  1327.             chr = str[i];
  1328.             if ((chr >= '0') && (chr <= '9'))
  1329.                 gTimerThreshold = gTimerThreshold*10 + chr - '0';
  1330.         }
  1331.         
  1332.         if (gTimerThreshold != 0)
  1333.         {
  1334.             done = true;
  1335.             fprintf(stdout, "\n The timer threshold is set at %ld\n\n", gTimerThreshold);
  1336.             fflush(stdout);
  1337.         }
  1338.     }
  1339. }
  1340.  
  1341. /*
  1342.     The following routine prints the name of the port currently being used by AppleTalk
  1343.     If AppleTalk is using Ethernet, then the fPortName field could be used in the 
  1344.     OpenEndpoint call to open an ethernet endpoint on the same hardware port as AppleTalk
  1345. */
  1346. void PrintAppleTalkPortName(void)
  1347. {
  1348.     ATSvcRef            atref;
  1349.     OSStatus            err;
  1350.     OTPortRef            portref;
  1351.     OTPortRecord        portrecord;
  1352.     TEndpointInfo        info;
  1353.     
  1354.     atref = OTOpenEndpoint(OTCreateConfiguration(kDDPName), 0, &info, &err);
  1355.     
  1356.     if (err == kOTNoError)
  1357.     {
  1358.         portref = OTGetProviderPortRef(atref);
  1359.         if (portref != nil)
  1360.         {
  1361.             if (OTFindPortByRef(&portrecord, portref) == true)
  1362.             {
  1363. //                fprintf(stderr, "\n Appletalk port name is %s", portrecord.fPortName);
  1364.                 portref = portrecord.fChildPorts[0];
  1365.                 if (OTFindPortByRef(&portrecord, portref) == true)
  1366.                     fprintf(stdout, "\n Appletalk child port name is %s", portrecord.fPortName);
  1367.                 else
  1368.                     fprintf(stdout, "\n Appletalk child port record could not be found using PortRef %lX", portref);
  1369.             }
  1370.             else
  1371.                 fprintf(stdout, "\n Appletalk port record could not be found using PortRef %lX", portref);
  1372.         }
  1373.         else
  1374.             fprintf(stdout, "\n OTGetProviderPortRef returned nil result");
  1375.             
  1376.         OTCloseProvider(atref);
  1377.     }
  1378.     else
  1379.         fprintf(stdout, "\n OTOpenAppleTalkServices returned error %d", err);
  1380.         
  1381.  
  1382. }
  1383.  
  1384. void ListEnetDrivers(void)
  1385. {
  1386.     OTPortRecord    portRecord;
  1387.     Boolean            foundAPort;
  1388.     UInt32            index;
  1389.     Str255            userFriendlyName;
  1390.     
  1391.     fprintf(stdout, "\n The list of drivers present is:\n");        
  1392.     index = 0;
  1393.         // iterate thru each OT port record for ethernet ports.    
  1394.     while (foundAPort = OTGetIndexedPort(&portRecord,index))
  1395.     {
  1396.         if ((portRecord.fCapabilities & kOTPortIsDLPI) &&
  1397.             (portRecord.fCapabilities & kOTPortIsTPI) &&
  1398.             (kOTEthernetDevice == OTGetDeviceTypeFromPortRef(portRecord.fRef)))
  1399.         {
  1400.             OTGetUserPortNameFromPortRef(portRecord.fRef, userFriendlyName);
  1401.             fprintf(stdout, "\n Driver name - %s, ", portRecord.fPortName);
  1402.             fprintf(stdout, "user readable name is - %#s", userFriendlyName);
  1403.                 
  1404.         }
  1405.         index++;
  1406.     }
  1407.     fprintf(stdout, "\n");    
  1408.     
  1409. }
  1410.